package com.slz3.business.frame.api.wx;

import com.slz3.business.frame.api.alipay.AliPayUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.*;

/**
 * @FileName: WeixinUtil
 * @Description: 微信退款及查询工具类
 */

@Slf4j
public class WeixinUtil {

    // 统一下单
    private static final String ORDER_PAY = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    // 支付订单查询
    private static final String ORDER_PAY_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";

    // 申请退款
    private static final String ORDER_REFUND = "https://api.mch.weixin.qq.com/secapi/pay/refund";

    // 申请退款查询
    private static final String ORDER_REFUND_QUERY = "https://api.mch.weixin.qq.com/pay/refundquery";

    private static final String APP_ID = "wxe43cfe74061aaff1";

    private static final String MCH_ID = "1510891941";

    private static final String KEY = "mishangkejiyouxiangongsi2018app2";

    public static void main(String[] args){
//        orderPayQuery("20180810164916417");
//        orderPayRefund("20180810164916417",0.01,0.01,"微信测试退款");
//        "out_refund_no" -> "RNO2018081417474345900000001"
        orderPayRefundQuery("20180810164916417");
    }

    /**
     * 查询支付结果
     * @param tradeno 商品订单号
     */
    public static Map<String, String> orderPayQuery( String tradeno) {
        log.info("orderPayQuery");

        Map<String, String> restmap = null;
        try {
            Map<String, String> parm = new HashMap<String, String>();
            parm.put("appid", APP_ID);
            parm.put("mch_id", MCH_ID);
            parm.put("out_trade_no", tradeno);
            parm.put("nonce_str", getNonceStr());
            parm.put("sign",getSign(parm));

            String restxml = HttpUtils.post(ORDER_PAY_QUERY, XmlUtil.xmlFormat(parm, false));
            restmap = XmlUtil.xmlParse(restxml);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        if (null!=restmap&&restmap.size()>0 && "SUCCESS".equals(restmap.get("result_code"))) {
            // 订单查询成功 处理业务逻辑
            log.info("订单查询：订单" + restmap.get("out_trade_no") + "支付成功");
        } else {
            if (null!=restmap&&restmap.size()>0) {
                log.info("订单支付失败：" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            }
        }
        return restmap;
    }

    /**
     * 订单退款 需要双向证书验证
     *
     * @param orderno  商家订单号
     */
    public static Map<String, String> orderPayRefund(String orderno,double total_fee,double refund_fee,String refund_desc) {
//        log.info("orderPayRefund");

        Map<String, String> restmap = null;
        try {
            Map<String, String> parm = new HashMap<String, String>();
            parm.put("appid", APP_ID);
            parm.put("mch_id", MCH_ID);
            parm.put("nonce_str", getNonceStr());
            //订单号
            parm.put("out_trade_no", orderno);
            //退款单号
            parm.put("out_refund_no", AliPayUtil.getRefundNo());
            int totalFee = 0;
            if (total_fee>0){
                total_fee = total_fee*100;
                totalFee=(int)total_fee;
            }
            int refundFee = 0;
            if (refund_fee>0){
                refund_fee = refund_fee*100;
                refundFee=(int)refund_fee;
            }
            // 订单总金额 从业务逻辑获取
            parm.put("total_fee", String.valueOf(totalFee));
            // 退款金额
            parm.put("refund_fee", String.valueOf(refundFee));
            //退款原因
            parm.put("refund_desc", refund_desc);
            parm.put("sign", getSign(parm));

            String restxml = HttpUtils.posts(ORDER_REFUND, XmlUtil.xmlFormat(parm, false));
            restmap = XmlUtil.xmlParse(restxml);
        } catch (Exception e) {
//            log.error(e.getMessage(), e);
        }

        Map<String, String> refundMap = new HashMap<>();
        if (null!=restmap&&restmap.size()>0 && "SUCCESS".equals(restmap.get("result_code"))) {
            refundMap.put("transaction_id", restmap.get("transaction_id"));
            refundMap.put("out_trade_no", restmap.get("out_trade_no"));
            refundMap.put("refund_id", restmap.get("refund_id"));
            refundMap.put("out_refund_no", restmap.get("out_refund_no"));
//            log.info("订单退款：订单" + restmap.get("out_trade_no") + "退款成功，商户退款单号" + restmap.get("out_refund_no") + "，微信退款单号"
//                    + restmap.get("refund_id"));
        } else {
            if (null!=restmap&&restmap.size()>0 ) {
//                log.info("订单退款失败：" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            }
        }
        return restmap;
    }

    /**
     * 订单退款查询
     * @param tradeno 微信订单号.商户订单号,微信退款号,商家退款号 四选一
     */
    public static Map<String, String> orderPayRefundQuery(String tradeno) {
//        log.info("orderPayRefundQuery");

        Map<String, String> restmap = null;
        try {
            Map<String, String> parm = new HashMap<String, String>();
            parm.put("appid", APP_ID);
            parm.put("mch_id", MCH_ID);
            parm.put("nonce_str", getNonceStr());
            // 微信订单号.商户订单号,微信退款号,商家退款号 四选一
            parm.put("out_trade_no", tradeno);
            parm.put("sign", getSign(parm));

            String restxml = HttpUtils.post(ORDER_REFUND_QUERY, XmlUtil.xmlFormat(parm, false));
            restmap = XmlUtil.xmlParse(restxml);
        } catch (Exception e) {
//            log.error(e.getMessage(), e);
        }

        Map<String, String> refundMap = new HashMap<>();
        if (null!=restmap&&restmap.size()>0 && "SUCCESS".equals(restmap.get("result_code")) && "SUCCESS".equals(restmap.get("result_code"))) {
            // 订单退款查询成功 处理业务逻辑
//            log.info("退款订单查询：订单" + restmap.get("out_trade_no") + "退款成功，退款状态"+ restmap.get("refund_status_0"));
            refundMap.put("transaction_id", restmap.get("transaction_id"));
            refundMap.put("out_trade_no", restmap.get("out_trade_no"));
            refundMap.put("refund_id", restmap.get("refund_id_0"));
            refundMap.put("refund_no", restmap.get("out_refund_no_0"));
            refundMap.put("refund_status", restmap.get("refund_status_0"));
        } else {
            if (null!=restmap&&restmap.size()>0) {
//                log.info("订单退款失败：" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            }
        }
        return restmap;
    }

    /**
     * 构造签名
     *
     * @param params
     */
    private static String getSign(Map<String, String> params){
        MessageDigest messageDigest = null;
        try {
            Set<String> keysSet = params.keySet();
            Object[] keys = keysSet.toArray();
            Arrays.sort(keys);
            StringBuffer temp = new StringBuffer();
            boolean first = true;
            for (Object key : keys) {
                // 参数为空不参与签名
                if (key == null || null==params.get(key)||"".equals(params.get(key))){
                    continue;
                }
                if (first) {
                    first = false;
                } else {
                    temp.append("&");
                }
                temp.append(key).append("=");
                Object value = params.get(key);
                String valueStr = "";
                if (null != value) {
                    valueStr = value.toString();
                }
                if (false) {
                    temp.append(URLEncoder.encode(valueStr, "UTF-8"));
                } else {
                    temp.append(valueStr);
                }
            }
            String content = temp.toString()+"&key="+KEY;
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(content.getBytes("UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        byte[] byteArray = messageDigest.digest();

        StringBuffer md5StrBuff = new StringBuffer();

        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1){
                md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
            }else{
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
            }
        }

        return md5StrBuff.toString().toUpperCase();
    }

    /**
     * 创建支付随机字符串
     * @return
     */
    public static String getNonceStr(){
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < 32; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }
}